package com.terren.statistic.common.util;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import org.apache.log4j.Logger;

public class FileOperateUtils {

	/**
	 * @description：得到目录下的所有文件的路径
	 * @param dir :要分析的文件夹的路径
	 * @return：文件夹中所有文件的绝对路径集合
	 * @throws Exception
	 * @author tanshuguo
	 */
	static ArrayList<String> allFilesPath = new ArrayList<String>();
	
	static Logger log = LogUtil.getLogger(FileOperateUtils.class);

	public static ArrayList<String> getAllFilesPath(File dir) {

		if (!dir.isDirectory()) {
			String filePath = dir.getAbsolutePath();
			System.out.println(filePath);
			allFilesPath.add(filePath);
		} else {
			File[] fs = dir.listFiles();
			for (int i = 0; i < fs.length; i++) {
				if (fs[i].isDirectory()) {
					try {
						getAllFilesPath(fs[i]);
					} catch (Exception e) {
						log.error("FileOperateUtils.getAllFilesPath error" + e.getMessage());
					}
				} else {
					String filePath = fs[i].getAbsolutePath();
					log.info(filePath);
					allFilesPath.add(filePath);
				}
			}
		}
		log.info("Utils.getAllFilesPath-文件个数---->" + allFilesPath.size());
		return allFilesPath;
	}

	/**
	 * @description：得到文件内容
	 * @param filePath :要读取的文件路径
	 * @return 返回文件内容
	 * @author tanshuguo
	 */
	public static String getFileContent(String filePath) {
		StringBuffer sb = new StringBuffer();
		InputStreamReader isr = null;
		BufferedReader bufferedReader = null;
		// String fileContent="";
		try {
			String encoding = "utf-8";
			File file = new File(filePath);
			if (file.isFile() && file.exists()) { // 判断文件是否存在
				isr = new InputStreamReader(new FileInputStream(file), encoding);// 考虑到编码格式
				bufferedReader = new BufferedReader(isr);
				String lineTxt = null;
				while ((lineTxt = bufferedReader.readLine()) != null) {
					sb.append(lineTxt);
				}
				isr.close();
			} else {
				log.info("找不到指定的文件");
			}
		} catch (Exception e) {
			log.info("读取文件内容出错:" + e.getMessage());
			e.printStackTrace();
		} finally {
			try {
				if (isr != null) {
					isr.close();
					isr = null;
				}
				if (bufferedReader != null) {
					bufferedReader.close();
					bufferedReader = null;
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return sb.toString();
	}

	/**
	 * @description：得到文件内容
	 * @param filePath :要读取的文件路径
	 * @return 返回文件内容
	 * @author tanshuguo
	 */
	public static String getFileContent(String filePath, String encode) {
		StringBuffer sb = new StringBuffer();
		InputStreamReader isr = null;
		BufferedReader bufferedReader = null;
		try {
			String encoding = encode;
			File file = new File(filePath);
			if (file.isFile() && file.exists()) { // 判断文件是否存在
				isr = new InputStreamReader(new FileInputStream(file), encoding);// 考虑到编码格式
				bufferedReader = new BufferedReader(isr);
				String lineTxt = null;
				while ((lineTxt = bufferedReader.readLine()) != null) {
					sb.append(lineTxt);
				}
				isr.close();
			} else {
				log.info("找不到指定的文件");
			}
		} catch (Exception e) {
			log.info("读取文件内容出错:" + e.getMessage());
			e.printStackTrace();
		} finally {
			try {
				if (isr != null) {
					isr.close();
					isr = null;
				}
				if (bufferedReader != null) {
					bufferedReader.close();
					bufferedReader = null;
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return sb.toString();
	}

	/**
	 * 获得文件的字节数组
	 * 
	 * @param filename
	 * @return
	 * @throws IOException
	 */
	public static byte[] getByteFromFile(String filename) throws IOException {
		File f = new File(filename);
		if (!f.exists()) {
			throw new FileNotFoundException(filename);
		}
		ByteArrayOutputStream bos = new ByteArrayOutputStream((int) f.length());
		BufferedInputStream in = null;
		try {
			in = new BufferedInputStream(new FileInputStream(f));
			int buf_size = 1024;
			byte[] buffer = new byte[buf_size];
			int len = 0;
			while (-1 != (len = in.read(buffer, 0, buf_size))) {
				bos.write(buffer, 0, len);
			}
			return bos.toByteArray();
		} catch (IOException e) {
			e.printStackTrace();
			throw e;
		} finally {
			try {
				in.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			bos.close();
		}
	}

	/**
	 * @decription:把data写入targetFilePath中
	 * @param data           ：要写入的内容，采用编码为：utf-8
	 * @param targetFilePath ：要写入到的文件路径
	 * @author tanshuguo
	 */
	public static void writeFile(String data, String targetFilePath) {
		OutputStreamWriter osw = null;
		BufferedWriter output = null;
		FileOutputStream fos = null;
		String encoding = "utf-8";
		try {
			File file = new File(targetFilePath);
			if (file.exists()) {
				log.info("Utils.writeFile--文件存在，追加内容");
				fos = new FileOutputStream(file, true);
				osw = new OutputStreamWriter(fos, encoding);// 考虑到编码格式
				output = new BufferedWriter(osw);
				output.write(data + "\r\n");
			} else {
				log.info("Utils.writeFile--文件不存在--已创建");
				File parentOfFile = file.getParentFile();
				if (!parentOfFile.exists()) {
					parentOfFile.mkdirs();
					log.info("Utils--writeFile--存储文件父路径-->" + parentOfFile.getPath());

				}
				// file.mkdirs();
				file.createNewFile();// 不存在则创建
				fos = new FileOutputStream(file, true);
				osw = new OutputStreamWriter(fos, encoding);// 考虑到编码格式
				output = new BufferedWriter(osw);
				output.write(data + "\r\n");
			}

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (output != null) {
					output.close();
					output = null;
				}
				if (osw != null) {
					osw.close();
					osw = null;
				}
				if (fos != null) {
					fos.close();
					fos = null;
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 
	 * @decription:把data写入targetFilePath中
	 * @param data           ：要写入的内容，采用编码为：utf-8
	 * @param targetFilePath ：要写入到的文件路径
	 * @param                encoding:写文件时要采用的编码格式
	 */
	public static void writeFile(String data, String targetFilePath, String encoding) {
		OutputStreamWriter osw = null;
		BufferedWriter output = null;
		FileOutputStream fos = null;
		try {
			File file = new File(targetFilePath);
			if (file.exists()) {
				log.info("Utils.writeFile--文件存在，追加内容");
				fos = new FileOutputStream(file, true);
				osw = new OutputStreamWriter(fos, encoding);// 考虑到编码格式
				output = new BufferedWriter(osw);
				output.write(data + "\r\n");
			} else {
				log.info("Utils.writeFile--文件不存在--已创建");
				File parentOfFile = file.getParentFile();
				if (!parentOfFile.exists()) {
					parentOfFile.mkdirs();
					log.info("Utils--writeFile--存储文件父路径-->" + parentOfFile.getPath());

				}
				// file.mkdirs();
				file.createNewFile();// 不存在则创建
				fos = new FileOutputStream(file, true);
				osw = new OutputStreamWriter(fos, encoding);// 考虑到编码格式
				output = new BufferedWriter(osw);
				output.write(data + "\r\n");
			}

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (output != null) {
					output.close();
					output = null;
				}
				if (osw != null) {
					osw.close();
					osw = null;
				}
				if (fos != null) {
					fos.close();
					fos = null;
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 
	 * @decription:把data写入targetFilePath中
	 * @param data           ：要写入的内容
	 * @param targetFilePath ：要写入到的文件路径
	 * @param                encoding:写文件时要采用的编码格式
	 */
	public static void writeFileNotAppend(String data, String targetFilePath, String encoding) {
		OutputStreamWriter osw = null;
		BufferedWriter output = null;
		FileOutputStream fos = null;

		try {
			File file = new File(targetFilePath);
			if (file.exists()) {
				log.info("--writeFileNotAppend--->文件已存在");
				file.delete();
				log.info("--writeFileNotAppend--->文件已删除");
			}
			log.info("--writeFileNotAppend--->文件已创建");
			File parentOfFile = file.getParentFile();
			if (!parentOfFile.exists()) {
				parentOfFile.mkdirs();
				log.info("--writeFileNotAppend--->存储文件父路径-->" + parentOfFile.getPath());

			}
			// file.mkdirs();
			file.createNewFile();// 不存在则创建
			fos = new FileOutputStream(file, true);
			osw = new OutputStreamWriter(fos, encoding);// 考虑到编码格式
			output = new BufferedWriter(osw);
			output.write(data + "\r\n");

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (output != null) {
					output.close();
					output = null;
				}
				if (osw != null) {
					osw.close();
					osw = null;
				}
				if (fos != null) {
					fos.close();
					fos = null;
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 
	 * @param zhStr 需要得到unicode编码的字符串
	 * @return unicode编码的字符串
	 */
	public static String getUnicodeFromStr(String zhStr) {
		StringBuffer unicode = new StringBuffer();
		for (int i = 0; i < zhStr.length(); i++) {
			char c = zhStr.charAt(i);
			unicode.append("\\u" + Integer.toHexString(c));
		}
		return unicode.toString();
	}

	/**
	 * 
	 * @param unicode 字符的unicode编码：例如北京欢迎你的unicode编码为：\u5317\u4eac\u6b22\u8fce\u4f60
	 * @return 返回字符串：如北京欢迎你
	 */
	public static String getStrFromUnicode(String unicode) {
		StringBuffer sb = new StringBuffer();
		String[] hex = unicode.split("\\\\u"); // \不是"\\u"，而是 "\\\\u"
		for (int i = 1; i < hex.length; i++) { // 注意要从 1 开始，而不是从0开始。第一个是空。
			int data = Integer.parseInt(hex[i], 16); // 将16进制数转换为 10进制的数据。
			sb.append((char) data); // 强制转换为char类型就是我们的中文字符了。
		}

		return sb.toString();
	}

	/**
	 * 创建文件夹
	 * 
	 * @param path
	 */
	public static void mkdirs(String path) {
		File file = new File(path);
		if (!file.exists()) {
			file.mkdirs();
		}
	}

	/**
	 * 
	 * @param srcDir 压缩文件夹路径 
	 * @param out 压缩文件输出流
	 * @param KeepDirStructure 是否保留原来的目录结构,true:保留目录结构; false:所有文件跑到压缩包根目录下(注意：不保留目录结构可能会出现同名文件,会压缩失败)
	 * @throws RuntimeException
	 */
	public static Boolean toZip(String srcDir, OutputStream out, boolean KeepDirStructure) throws RuntimeException {
		ZipOutputStream zos = null;
		Boolean flag = true;
		try {
			zos = new ZipOutputStream(out);
			File sourceFile = new File(srcDir);
			compress(sourceFile, zos, sourceFile.getName(), KeepDirStructure);
		} catch (Exception e) {
			flag = false;
			throw new RuntimeException("zip error from ZipUtils", e);
		} finally {
			if (zos != null) {
				try {
					zos.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return flag;
	}

	private static void compress(File sourceFile, ZipOutputStream zos, String name, boolean KeepDirStructure)
			throws Exception {
		byte[] buf = new byte[2 * 1024];
		if (sourceFile.isFile()) {
			// 向zip输出流中添加一个zip实体，构造器中name为zip实体的文件的名字
			zos.putNextEntry(new ZipEntry(name));
			// copy文件到zip输出流中
			int len;
			FileInputStream in = new FileInputStream(sourceFile);
			while ((len = in.read(buf)) != -1) {
				zos.write(buf, 0, len);
			}
			zos.closeEntry();
			in.close();
		} else {
			File[] listFiles = sourceFile.listFiles();
			if (listFiles == null || listFiles.length == 0) {
				// 需要保留原来的文件结构时,需要对空文件夹进行处理
				if (KeepDirStructure) {
					// 空文件夹的处理
					zos.putNextEntry(new ZipEntry(name + "/"));
					// 没有文件，不需要文件的copy
					zos.closeEntry();
				}
			} else {
				for (File file : listFiles) {
					// 判断是否需要保留原来的文件结构
					if (KeepDirStructure) {
						// file.getName()前面需要带上父文件夹的名字加一斜杠,不然最后压缩包中就不能保留原来的文件结构,即：所有文件都跑到压缩包根目录下了
						compress(file, zos, name + "/" + file.getName(), KeepDirStructure);
					} else {
						compress(file, zos, file.getName(), KeepDirStructure);
					}
				}
			}
		}
	}
}